package eMdP.estats;

import com.acarter.scenemonitor.SceneMonitor;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;

import java.net.URL;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.logging.Logger;

import jmetest.renderer.TestSkybox;

import com.jme.image.Texture;
import com.jme.input.InputHandler;
import com.jme.input.MouseInput;
import com.jme.light.PointLight;

import com.jme.scene.Node;
import com.jme.scene.Skybox;
import com.jme.scene.Text;
import com.jme.scene.state.LightState;
import com.jme.util.BoneDebugger;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.bui.BComponent;
import com.jmex.bui.BContainer;
import com.jmex.bui.BImage;
import com.jmex.bui.BLabel;
import com.jmex.bui.background.ImageBackground;
import com.jmex.bui.enumeratedConstants.ImageBackgroundMode;
import com.jmex.bui.util.Point;

import eMdP.classesBasiques.Bustia;
import eMdP.classesBasiques.Escenari;
import eMdP.classesBasiques.Furgoneta;
import eMdP.classesBasiques.Personatge;
import eMdP.classesBasiques.PersonatgeNJ;
import eMdP.colisions.ImplCallBack;
import eMdP.gestors.GestorConstants;
import eMdP.gestors.GestorFitxers;
import eMdP.gestors.GestorMusica;
import eMdP.gestors.GestorPantalla;
import eMdP.inputHandler.EMdPHandler;
/**
 * Started Date: 10 Juny 2009<br><br>
 * Continued: 16 July 2009<br><br>
 * 
 * 
 * @author Peppino Coorp
 */
public class Partida extends GbuiGameState {
	
	 private static final Logger logger = Logger
     .getLogger(Partida.class.getName());

	private Text infotext;
	private Text temporitzador;
	private Text paquetsE;
	
	private Node statNode;
	
	private Timer timer;
	private InputHandler[] inputeta;
	
	//private DeteccioColisions dp;
	
	private Camera cam;

	private PointLight pLight;
	private	LightState lState;
	
	private LinkedList<Bustia> busties = new LinkedList<Bustia>();
	private LinkedList<PersonatgeNJ> pnjs = new LinkedList<PersonatgeNJ>();
	private LinkedList<Furgoneta> furgonetes = new LinkedList<Furgoneta>();
	private LinkedList<Personatge> jugadors = new LinkedList<Personatge>();
	private Escenari escenari;
	
	boolean sceneMonitor=false;
	
	/* Variables de la Partida */
	private int iniciJoc;
	private int tipusJoc;
	private float tempsPerPartida = GestorConstants.TEMPS_PER_PARTIDA;
	private boolean trobat = false; //Variable que ens indica si algun jugador ha superat els paquets a entrar
	private int jugadorGuanyador; //id del jugador que ha guanyat
	
	private Skybox skybox;
	/**
	 * Constructor d'una Partida Multijugador. A on el paràmetre idPersonatges conté la quantitat de personatges i la seva id
	 * per tal de poder buscar i carregar els models, sons, ... A part, també ens passen per paràmetre la id de l'escenari i el 
	 * mode de joc.
	 * @param idPersonatges Conté la id dels personatges per tal de carregar els models, sons, ...
	 * @param idEscenari Conté la id d'escenari, que ens servirà per carregar-lo
	 * @param mode Mode de joc, 0 -> Hem de llançar 15 Paquets en els menor temps possible i 1 -> Màxim de Paquets en 300 segons
	 */
	public Partida(int[] idPersonatges, int idEscenari, int mode){
		super("Partida");
		int contador = 0;
		for(int i=0;i<idPersonatges.length;i++)
			if(idPersonatges[i] != -1)
				contador++;
		int[] personatges = new int[contador];
		for(int i=0;i<contador;i++)
			personatges[i] = idPersonatges[i];
		
		inicialitzemElements(personatges, idEscenari, mode);
	}
	
	/**
	 * Constructor d'una Partida Individual. A on el paràmetre idPersonatge conté únicament la id del Personatge per tal de poder
	 * buscar i carregar els models, sons, ... A part, també ens passen per paràmetre la id de l'escenari i el mode de joc.
	 * @param idPersonatge Conté la id dels personatges per tal de carregar els models, sons, ...
	 * @param idEscenari Conté la id d'escenari, que ens servirà per carregar-lo
	 * @param mode Mode de joc, 0 -> Hem de llançar 15 Paquets en els menor temps possible i 1 -> Màxim de Paquets en 300 segons
	 */
	public Partida(int idPersonatge, int idEscenari, int mode){
		super("Partida");
		int[] idPersonatges = new int[1];
		idPersonatges[0] = idPersonatge;
		System.out.println("Em escollit personatge: "+idPersonatge+" i escenari: "+idEscenari);
		inicialitzemElements(idPersonatges, idEscenari, mode);
		
	}
	
	
	private void inicialitzemElements(int[] idPersonatges, int idEscenari, int mode){
		if(sceneMonitor){
			SceneMonitor.getMonitor().registerNode(rootNode, "Root Node");
			SceneMonitor.getMonitor().showViewer(true);
		}
		
		/*Fem visible el ratolí */
    	MouseInput.get().setCursorVisible(true);
    	
    	/* Assignem el mode de joc a la variable de la Partida */
		tipusJoc = mode;
		
		creemEscenari(idEscenari);
		creemJugadors(idPersonatges);
		creemBusties();
		creeemPNJS();
		buildGui();
		creemFurgonetes();
		creemLlums();
		
		/* Un cop temim tots els personatges i objectes que participaran a la partida inicialitzem les opcions */
		/* Creem la càmera i la posicionem allà a on ens interessa */
    	creemCamera();
    	
    	/* Creem el control dels jugadors */
    	setupInput(idPersonatges.length);
    	
    	/* Creem les col·lisions */
    	setupColisions();
    	
    	/* Creem el timer */
    	timer = Timer.getTimer();
    	
    	/* Creem la gravetat */
    	getPhysicsSpace().setDirectionalGravity( new Vector3f( 0, -10, 0 ) );
    	
    	/* Creem la musica */
    	GestorMusica.CrearMusica(cam);
    	/* Reproduim la musica del joc */
    	GestorMusica.play();
    	
    	
    	/* Creem el Node estat, a on penjaran tots els textes que es mostraran per pantalla */
        statNode = new Node("estat");
        creemTextosMostrarPantalla();
        
        /* Assignem l'statNode al rootNode */
        rootNode.attachChild(statNode);

       // buildSkyBox();
        iniciJoc = (int)timer.getTimeInSeconds();
	}
	
	private void creemEscenari(int id){
		escenari = GestorFitxers.carregarEscenari(id, getPhysicsSpace());
		rootNode.attachChild(escenari);
	}
	
	private void creemBusties(){
		Bustia a;
		for(int i=0;i<escenari.getNumBusties();i++){
			a = new Bustia("Bustia"+i,GestorConstants.DIRECCIO_BUSTIA,i,getPhysicsSpace().createStaticNode());
			a.setLocalTranslation(escenari.getPosBusties().get(i));
			escenari.attachChild(a);
			busties.add(a);
			System.out.println("Això és la bustia: "+i);
		}
	}
	
	private void creeemPNJS(){
		PersonatgeNJ p;
		
		for(int i=0;i<escenari.getNumPNJS();i++){
			p = new PersonatgeNJ("NJ"+i,20,getPhysicsSpace(),0.8f,4+i);
			//p.setLocalScale(0.2f);
			p.setLocalTranslation(escenari.getPosPNJS().get(i).add(0, 1, 0));
			p.lookAt(new Vector3f(0,0,0), new Vector3f(0,1,0));
			p.setLocalScale(3);
			escenari.attachChild(p);
			//color(p,ColorRGBA.red);
			pnjs.add(p);
		}	
	}

	private void creemFurgonetes(){
		Furgoneta g;
		for(int i=0;i<escenari.getNumFurgos();i++){
			Vector3f posFinal = new Vector3f();
			Vector3f posArribada = escenari.getPosFurgonetes().get(i);
			if(posArribada.x>0)
				posFinal.set(escenari.getPosFurgonetes().get(i)).addLocal(50, 0, 0);
			else
				posFinal.set(escenari.getPosFurgonetes().get(i)).addLocal(-50, 0, 0);
			
			g = new Furgoneta("FurgoCorreus"+i,getPhysicsSpace().createStaticNode(),posArribada,posFinal,true);
			g.setLocalTranslation(posArribada);
			escenari.attachChild(g);
			furgonetes.add(g);
		}
	}

	private void creemJugadors(int[] idsPersonatges){
		Personatge a;
		//System.out.println("Les ids dels personatges son: ");
		for(int i=0;i<idsPersonatges.length;i++){
			//System.out.print(idsPersonatges[i]+", ");
			a = GestorFitxers.carregarPersonatge(idsPersonatges[i], getPhysicsSpace());
			a.setIdJugador(i);
			a.setLocalTranslation(escenari.getPosJugadors().get(i));
			a.mirarAlCentre();
			a.setLocalScale(3.3f);
			escenari.attachChild(a);
			jugadors.add(a);
		}
	}
	
	private void creemLlums(){
		
		pLight = new PointLight();
    	pLight.setLocation(new Vector3f(15,50,-15));
    	//pLight.setDiffuse(ColorRGBA.red);
    	
    	pLight.setAmbient(ColorRGBA.white);
    	pLight.setAttenuate(false);
    	pLight.setConstant(5);
    	pLight.setEnabled(true);
    	lState = display.getRenderer().createLightState();
    	lState.attach(pLight);
    	rootNode.setRenderState(lState);
    	
        rootNode.updateRenderState();
	}
	
	private void setupInput(int numInputs) {
		inputeta = new EMdPHandler[numInputs];
		for(int i=0;i<numInputs;i++){
	    	 HashMap<String, Object> handlerProps = new HashMap<String, Object>();
	         handlerProps.put(EMdPHandler.PROP_DOGRADUAL, "true");
	         handlerProps.put(EMdPHandler.PROP_TURNSPEED, ""+(1.5f * FastMath.PI));
	         handlerProps.put(EMdPHandler.PROP_CONTROL_ENTRADA, i);
	         //Hauriem d'anar a buscar unes constants per definir els controls de cada jugador
	         //De moment tots es mouen amb IKLJ
	         inputeta[i] = new EMdPHandler(jugadors.get(i),cam,handlerProps,getPhysicsSpace());
	         inputeta[i].setActionSpeed(30f);
		} 
    }
	
	private void setupColisions(){
    	new ImplCallBack(getPhysicsSpace(),rootNode);
    	logger.info("PARTIDA::Instal·lem el detector de col·lisions");
    }
	
	private void creemCamera(){
		cam = display.getRenderer().getCamera();
		cam.setLocation(new Vector3f(0,160,-230));
		cam.lookAt(new Vector3f(0,-25,0), new Vector3f(0,1,0));
    	cam.update();
	}
	
	private void creemTextosMostrarPantalla(){
		infotext = Text.createDefaultTextLabel("text informatiu");
        infotext.getLocalTranslation().set( 0, 20, 0 );
        statNode.attachChild( infotext );
          
        temporitzador = Text.createDefaultTextLabel("Temporitzador");
        temporitzador.getLocalTranslation().set( display.getWidth()/2, display.getHeight()-20, 0 );
        statNode.attachChild( temporitzador );
          
        paquetsE = Text.createDefaultTextLabel("Paquets entrats");
        paquetsE.getLocalTranslation().set(10, display.getHeight()-20, 0 );
        statNode.attachChild( paquetsE );
	}
	
	@Override
	public void update(float tpf){
		super.update(tpf);
		
		// Posem animacio d'estar caminant (si cal)
		for(int i=0;i<jugadors.size();i++)
		{
			if(jugadors.get(i).haAcabatDeTirar() && !jugadors.get(i).estaCaminant() && !jugadors.get(i).estaEsperant())
				jugadors.get(i).posaCaminant();
		}
		
		int nombre = GestorPantalla.getLlista().getLast().getFinestra().getComponentCount();
		int temps = (int)timer.getTimeInSeconds()-iniciJoc;
		if(tipusJoc == GestorConstants.MODE_PAQUETS)
			((BLabel)GestorPantalla.getLlista().getLast().getFinestra().getComponent(nombre-1)).setText(temps+" s");
		else
			((BLabel)GestorPantalla.getLlista().getLast().getFinestra().getComponent(nombre-1)).setText((tempsPerPartida - temps)+" s");
		
		cam.update();
		if((tipusJoc == GestorConstants.MODE_PAQUETS && !trobat) 
				|| (tipusJoc == GestorConstants.MODE_TEMPS && (tempsPerPartida - temps) > 0))
    	{ 
	        
			/* Actualitzem la posició de les furgonetes i dels Personatges No Jugadors */
			for(int i=0;i<furgonetes.size();i++)
				furgonetes.get(i).actualitzar(timer.getTimeInSeconds());
			
			
			for(int i=0;i<pnjs.size();i++)
				pnjs.get(i).actualitzar(timer.getTimeInSeconds());
	        
	    	
			for(int i=0;i<jugadors.size();i++){
				inputeta[i].update(timer.getTimePerFrame());
			}
	    	int i=0;
	    	while(i<jugadors.size() && !trobat){
	    		trobat = jugadors.get(i).quantsPaquetsHaEntrat() >= GestorConstants.PAQUETS_PER_PARTIDA;
	    		if(trobat)jugadorGuanyador=i;
	    		i++;
	    	}
    	}
		else
		{
    		GestorPantalla.guardarPuntuacions(jugadors.get(jugadorGuanyador), escenari.getNom(), tipusJoc, temps);
    	}	
		
		if(sceneMonitor)
			SceneMonitor.getMonitor().updateViewer(tpf);
		
	}
	
	@Override
	public void render(float tpf){
		super.render(tpf);
		//BoneDebugger.drawBones(rootNode, display.getRenderer(), true);
		if(sceneMonitor)
			SceneMonitor.getMonitor().renderViewer(display.getRenderer());
	}
	
	
	private void buildSkyBox() {
        skybox = new Skybox("skybox", 25, 25, 25);
 
        Texture north = TextureManager.loadTexture(
            TestSkybox.class.getClassLoader().getResource(
            "eMdP/skyboxes/nyDeNit/north.tga"),
            Texture.MinificationFilter.BilinearNearestMipMap,
            Texture.MagnificationFilter.Bilinear);
        Texture south = TextureManager.loadTexture(
            TestSkybox.class.getClassLoader().getResource(
            "eMdP/skyboxes/nyDeNit/south.tga"),
            Texture.MinificationFilter.BilinearNearestMipMap,
            Texture.MagnificationFilter.Bilinear);
        Texture east = TextureManager.loadTexture(
            TestSkybox.class.getClassLoader().getResource(
            "eMdP/skyboxes/nyDeNit/east.tga"),
            Texture.MinificationFilter.BilinearNearestMipMap,
            Texture.MagnificationFilter.Bilinear);
        Texture west = TextureManager.loadTexture(
            TestSkybox.class.getClassLoader().getResource(
            "eMdP/skyboxes/nyDeNit/west.tga"),
            Texture.MinificationFilter.BilinearNearestMipMap,
            Texture.MagnificationFilter.Bilinear);
        Texture up = TextureManager.loadTexture(
            TestSkybox.class.getClassLoader().getResource(
            "eMdP/skyboxes/nyDeNit/top.tga"),
            Texture.MinificationFilter.BilinearNearestMipMap,
            Texture.MagnificationFilter.Bilinear);
        Texture down = TextureManager.loadTexture(
            TestSkybox.class.getClassLoader().getResource(
            "eMdP/skyboxes/nyDeNit/bottom.tga"),
            Texture.MinificationFilter.BilinearNearestMipMap,
            Texture.MagnificationFilter.Bilinear);
 
        skybox.setTexture(Skybox.Face.North, north);
        skybox.setTexture(Skybox.Face.West, west);
        skybox.setTexture(Skybox.Face.South, south);
        skybox.setTexture(Skybox.Face.East, east);
        skybox.setTexture(Skybox.Face.Up, up);
        skybox.setTexture(Skybox.Face.Down, down);
        skybox.getLocalTranslation().addLocal(0, 10, 0);
        skybox.preloadTextures();
        skybox.updateRenderState();
        rootNode.attachChild(skybox);
    }
	
	private void buildGui()
	{
		window.setSize((int)(display.getWidth()),(int)(display.getHeight()));
		
		// Contador:
		BLabel contador = new BLabel("0 s");
		contador.setPreferredSize(GestorConstants.ALT_BOTO*2,GestorConstants.ALT_BOTO);
		
		
		BImage bustia; BImage paquet;
		URL urlBustia = Partida.class.getClassLoader().getResource(GestorConstants.DIRECCIO_IMATGE_BUSTIA);
		URL urlPaquet = Partida.class.getClassLoader().getResource(GestorConstants.DIRECCIO_IMATGE_PAQUET);
		BContainer contenidor;
		BLabel text;
		
		
		int unQuart = display.getWidth()/4;
		//int unVuite = display.getWidth()/8;
		int unSetze = display.getWidth()/16;
		
		for(int i = 0;i<jugadors.size();i++)
		{
			int posicioY = display.getHeight()-GestorConstants.ALT_BOTO-GestorConstants.ESPAI_ENTRE_ELEMENTS_GBUI;
			
			text = new BLabel(jugadors.get(i).getNom().substring(10));
			text.setPreferredSize(unQuart, GestorConstants.ALT_BOTO);
			window.add(text, new Point(unQuart*i, posicioY));
			
			posicioY = posicioY-GestorConstants.PIXELS_IMATGE_ICONA-GestorConstants.ESPAI_ENTRE_ELEMENTS_GBUI;
			
			try
		   	{
				bustia = new BImage(urlBustia);
				paquet = new BImage(urlPaquet);
				
				contenidor = new BContainer("Bustia");
				contenidor.setBackground(BComponent.DEFAULT, new ImageBackground(ImageBackgroundMode.SCALE_XY, bustia));
				contenidor.setPreferredSize(44, 44);
				contenidor.setHoverEnabled(false);
				window.add(contenidor, new Point(unQuart*i+unSetze, posicioY));
				text = new BLabel("0");
				window.add(text, new Point(unQuart*i+unSetze+44, posicioY));
				contenidor = new BContainer("Paquet");
				contenidor.setBackground(BComponent.DEFAULT, new ImageBackground(ImageBackgroundMode.SCALE_XY, paquet));
				contenidor.setPreferredSize(44, 44);
				contenidor.setHoverEnabled(false);
				window.add(contenidor, new Point(unQuart*i+unSetze,GestorConstants.ESPAI_ENTRE_ELEMENTS_GBUI));
				text = new BLabel("0");
				window.add(text, new Point(unQuart*i+unSetze+44, GestorConstants.ESPAI_ENTRE_ELEMENTS_GBUI));
				
		   	} catch (Exception e)
		   	{
		   		System.out.println("No entro dintre el try de les imatges!");
		   	};
		   	window.add(contador, new Point(display.getWidth()-GestorConstants.ALT_BOTO*2-10, display.getHeight()-GestorConstants.ALT_BOTO-5));
		}
	}
	
}


